package com.me.myFramework.myAop.aop400;

import com.me.myFramework.myAop.IBuy;
import com.me.myFramework.myAop.Xbox;
import com.me.myFramework.myAop.aop400.advice.method.AfterReturningAdvice;
import com.me.myFramework.myAop.aop400.advice.method.MethodBeforeAdvice;
import org.apache.commons.lang3.ArrayUtils;

import java.lang.reflect.Method;

/**
 * 自己实现 AOP-4：  <p></p>
 *
 * 责任链实现多切面：类似 FilterChain 借助责任链的执行器 链式执行
 *
 * @author ME
 * @date 2021/9/26
 */
public class MyAop400 {

    public static void main(String[] args) throws Throwable {
        ProxyFactory factory = new ProxyFactory(new Xbox());
        factory.addAdvisor(new DefaultPointcutAdvisor(new BeforeAdvice111()));
        factory.addAdvisor(new DefaultPointcutAdvisor(new AfterReturningAdvice222()));

        IBuy proxy = (IBuy) factory.getProxy(Thread.currentThread().getContextClassLoader());

        // ----------------------- toString() ---------------------------------
        // [AOP1] Object 方法不处理：toString
        // [AOP2] Object 方法不处理：toString
        // com.me.myFramework.myAop.Xbox@deb6432
        // toString 在 AOP2 之后输出是因为，toString 内部没有输出，我们是在切面执行完之后输出的结果
        System.out.println("\n----------------------- toString() ---------------------------------");
        System.out.println(proxy.toString());
        System.out.println();

        String result = proxy.buy("Tom");
    }

    /**
     * 方法前的增强111。
     * 现阶段是直接把 advice逻辑 写到了 MethodBeforeAdvice 的实现类中，
     * 后续继续抽象则需要通过反射调用。
     */
    static class BeforeAdvice111 implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            String methodName = method.getName();
            if (!"toString".equals(methodName) && !"hashCode".equals(methodName) && !"equals".equals(methodName)
                    && !"clone".equals(methodName)) {
                System.out.println("[AOP1] 就是想记录谁消费了：" + (ArrayUtils.isEmpty(args) ? "" : args[0]));
            }
        }
    }

    /**
     * 方法正常返回的增强222
     */
    static class AfterReturningAdvice222 implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
            String methodName = method.getName();
            if (!"toString".equals(methodName) && !"hashCode".equals(methodName) && !"equals".equals(methodName)
                    && !"clone".equals(methodName)) {
                System.out.println("[AOP2] 想看看买了啥：" + target.getClass().getSimpleName());
            }
        }
    }

}
